package com.ruoyi.extdata.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bizsys.domain.CustomerCrsReport;
import com.ruoyi.bizsys.domain.CustomerInfo;
import com.ruoyi.bizsys.domain.ExtIdentityResult;
import com.ruoyi.bizsys.domain.RealNameAuth;
import com.ruoyi.bizsys.service.ICustomerCrsReportService;
import com.ruoyi.bizsys.service.ICustomerInfoService;
import com.ruoyi.bizsys.service.IExtIdentityResultService;
import com.ruoyi.bizsys.service.IRealNameAuthService;
import com.ruoyi.common.config.ServerYml;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.extdata.common.Constants;
import com.ruoyi.extdata.common.ExtReqEnum;
import com.ruoyi.extdata.common.config.CrsConfig;
import com.ruoyi.extdata.domain.OkRequestVo;
import com.ruoyi.extdata.service.ICrsService;
import com.ruoyi.extdata.service.IExternalApiService;
import com.ruoyi.extdata.service.IFileService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.ruoyi.extdata.common.Constants.EXT_CREDIT_CRS;

@Slf4j
@Service
public class CrsServiceImpl implements ICrsService {

    @Autowired
    private IExternalApiService iExternalApiService;

    @Autowired
    private ICustomerCrsReportService crsReportService;

    @Autowired
    private IExtIdentityResultService extIdentityResultService;

    @Autowired
    private CrsConfig crsConfig;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IFileService fileService;

    @Autowired
    private ICustomerInfoService customerInfoService;

    @Autowired
    private IRealNameAuthService realNameAuthService;

    @Override
    public JSONObject authentication() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("EmailAddress", crsConfig.getEmailAddress());
        jsonObject.put("Password", crsConfig.getPassword());
        jsonObject.put("SubscriberID", crsConfig.getSubscriberId());
        JSONObject result = crsRequest(jsonObject, crsConfig.getLoginUrl(), "CRS-LOGIN", null);
        if (Func.isEmpty(result.get("SessionCode"))) {
            log.error("CRS登陆结果异常:{}", result.toString());
            throw new BusinessException(RspEnmu.SYSTEM_SYSDATA_EXCEPTION);
        }
        //保存登陆信息 90分钟有效
        redisCache.setCacheObject(EXT_CREDIT_CRS, result, 80, TimeUnit.MINUTES);
        return result;
    }

    @Override
    public String getSessionCode() {
        Object cacheObject = redisCache.getCacheObject(EXT_CREDIT_CRS);
        if (Func.isNotEmpty(cacheObject)) {
            return JSONObject.parseObject(cacheObject.toString()).get("SessionCode").toString();
        }
        return authentication().get("SessionCode").toString();
    }

    @Override
    public ExtIdentityResult findByBvn2(String userId, String bvn) {

        //本地判断是否存在 存在则直接获取
        ExtIdentityResult extIdentityResult = new ExtIdentityResult();
        extIdentityResult.setApiName("CRS-findByBvn2");
        extIdentityResult.setBvn(bvn);
        extIdentityResult.setState("1");
        List<ExtIdentityResult> extIdentityResults = extIdentityResultService.selectExtIdentityResultList(extIdentityResult);
        if (extIdentityResults.size() > 0) {
            return extIdentityResults.get(0);
        }

        JSONObject bindBvn2 = new JSONObject();
        bindBvn2.put("MaxRecords", 1);
        bindBvn2.put("MinRelevance", 1);
        bindBvn2.put("SessionCode", getSessionCode());
        bindBvn2.put("BVN", bvn);
        bindBvn2.put("GetNoMatchReport", "ifNoMatch");

        JSONObject result = crsRequest(bindBvn2, crsConfig.getFindByBVN2Url(), "CRS-findByBvn2", userId);
        String searchResult = result.get("SearchResult").toString();
        JSONArray array = JSONArray.parseArray(searchResult);
        if (array.size() == 0) {
            log.info("CRS-findByBvn2结果为空,bvn：{}", bvn);
            throw new BusinessException(result.get("Message").toString());
        }

        //封装ExtIdentityResult 缺account_number bank_code
        extIdentityResult.setCustNo(getCustNoByUserId(userId));
        JSONObject bvnJson = (JSONObject) array.get(0);
        extIdentityResult.setCrsRegistryId(bvnJson.get("RegistryID") + "");
        extIdentityResult.setUserId(userId);

        String name = commaConvertSpace(bvnJson.get("Name").toString());
        String[] names = name.split(" ");


        extIdentityResult.setFirstname(names.length > 0 ? names[0] : "");
        extIdentityResult.setMiddlename(names.length > 1 ? names[1] : "");
        extIdentityResult.setLastname(names.length > 2 ? names[2] : "");


        extIdentityResult.setGender(bvnJson.get("Gender").toString());
        extIdentityResult.setPhotoId(bvnJson.get("Picture").toString());
        //临时屏蔽报文
        //extIdentityResult.setReqResult(array.toString());

        //合并phone,生日
        Set<String> phoneSet = new HashSet<>();
        Set<String> dobsSet = new HashSet<>();
        Set<String> addressSet = new HashSet<>();
        Set<String> nameSet = new HashSet<>();
        for (int i = 0; i < array.size(); i++) {
            JSONObject item = (JSONObject) array.get(i);
            if (Func.isNotEmpty(item.get("Phone"))) {
                String[] phones = item.get("Phone").toString().replaceAll(" ", "").split(",");
                Arrays.stream(phones).forEach(p -> {
                    phoneSet.add(p);
                });
            }
            if (Func.isNotEmpty(item.get("DOBI"))) {
                dobsSet.add(item.get("DOBI").toString());
            }
            if (Func.isNotEmpty(item.get("Address"))) {
                addressSet.add(item.get("Address").toString());
            }
            if (Func.isNotEmpty(item.get("Name"))) {
                nameSet.add(commaConvertSpace(item.get("Name").toString()));
            }
        }
        //手机号码，生日
        List<String> ps = new ArrayList<>(phoneSet);
        extIdentityResult.setPhone1(ps.size() > 0 ? ps.get(0) : null);
        extIdentityResult.setPhone2(ps.size() > 1 ? ps.get(1) : null);
        extIdentityResult.setPhones(StringUtils.join(phoneSet, ","));
        extIdentityResult.setDob(StringUtils.join(dobsSet, ","));
        extIdentityResult.setFullname(StringUtils.join(nameSet, ","));
        List<String> ds = new ArrayList<>(addressSet);
        extIdentityResult.setAddress1(ds.size() > 0 ? ds.get(0) : null);
        extIdentityResult.setAddress2(StringUtils.join(addressSet, ","));

        //如果已经实名 则获取实名信息中的accountNumber等信息。然后直接新增CRS-findByBvn2实名信息。未实名说明当前在实名，把实体类返回去即可。
        RealNameAuth realNameAuth = new RealNameAuth();
        realNameAuth.setUserId(userId);
        List<RealNameAuth> realNameAuths = realNameAuthService.selectRealNameAuthList(realNameAuth);
        if (realNameAuths.size() == 0) {
            return extIdentityResult;
        }
        //已经实名
        realNameAuth = realNameAuths.get(0);
        extIdentityResult.setBvn(realNameAuth.getBvnAccount());
        extIdentityResult.setAccountNumber(realNameAuth.getAccountNumber());
        //生日或手机号码为空
        if (Func.hasEmpty(extIdentityResult.getPhones())) {
            extIdentityResult.setState("0");
        }

        try {
            ExtIdentityResult extIdentityResultQ = new ExtIdentityResult();
            extIdentityResultQ.setBvn(bvn);
            extIdentityResultQ.setState("1");
            List<ExtIdentityResult> extIdentityResultList = extIdentityResultService.selectExtIdentityResultList(extIdentityResultQ);
            extIdentityResult.setBankCode(extIdentityResultList.get(0).getBankCode());
            extIdentityResultService.insertExtIdentityResult(extIdentityResult);
        } catch (Exception e) {
            log.error("insertExtIdentityResult error", e);
            return extIdentityResult;
        }
        return extIdentityResult;
    }


    @Override
    public JSONObject getPaymentProfile(String accountOwnerIDs, String userId) {

        JSONObject payParams = new JSONObject();
        payParams.put("AccountOwnerIDs", accountOwnerIDs);
        payParams.put("SessionCode", getSessionCode());
        payParams.put("ReportReason", "credit");
        payParams.put("HistoryLengthInMonths", "24");
        JSONObject result = crsRequest(payParams, crsConfig.getPaymentProfileUrl(), "CRS-getPaymentProfile", userId);
        Object profile = result.get("CustomerPaymentProfile");
        if (Func.isEmpty(profile)) {
            log.info("CRS-PaymentProfile-查无信息，bvn:{}", accountOwnerIDs);
            throw new BusinessException(RspEnmu.EXTERNAL_API_RSP_NULL);
        }
        return JSONObject.parseObject(profile.toString());
    }

    @Override
    public JSONObject getData2(String accountOwnerIDs, String bvn, String userId) {
        JSONObject reportDataRequest = new JSONObject();
        //bvn查，与注册id无关
        reportDataRequest.put("BVN", bvn);
        reportDataRequest.put("AccountOwnerIDs", accountOwnerIDs);
        reportDataRequest.put("HistoryLengthInMonths", 24);
        reportDataRequest.put("SectorExclusionIDs", "");
        reportDataRequest.put("IncludeSMARTScore", true);
        reportDataRequest.put("IncludePDFReport ", true);
        reportDataRequest.put("PDFReportType", "None");
        reportDataRequest.put("Reason", "Credit");
        reportDataRequest.put("GetNoMatchReport", "IfNoMatch");
        JSONObject payParams = new JSONObject();
        payParams.put("SessionCode", getSessionCode());
        payParams.put("ReportDataRequest", reportDataRequest);
        JSONObject jsonObject = crsRequest(payParams, crsConfig.getData2Url(), "CRS-getData2", userId);
        if (jsonObject == null) {
            log.info("CRS-查无信息，bvn:{}", bvn);
            throw new BusinessException("");
        }
        return jsonObject;
    }

    @Override
    public CustomerCrsReport getConsumerFullCreditReport(String userId, String bvn) {
        try {
            ExtIdentityResult extIdentityResult = findByBvn2(userId, bvn);
            CustomerCrsReport crsReport = createCrsReportLocal(extIdentityResult.getCrsRegistryId(), userId, bvn);
            return crsReport;
        } catch (Exception e) {
            log.error("Crs报告异常，即将返回 null", e);
        }
        return null;
    }

    private CustomerCrsReport createCrsReportLocal(String registerId, String userId, String bvn) {
        return createCrsReport(registerId, userId, bvn);
    }

    @Async("threadPoolTaskExecutor")
    @Override
    public CustomerCrsReport createCrsReportAsync(String registerId, String userId, String bvn) {
        return createCrsReport(registerId, userId, bvn);
    }

    /**
     * 同类调用Async不会生效，依然是同步
     *
     * @param userId
     * @param bvn
     * @param registerId
     * @return
     */
    public CustomerCrsReport createCrsReport(String registerId, String userId, String bvn) {

        CustomerCrsReport crsReport = new CustomerCrsReport();
        try {
            JSONObject data2 = getData2("", bvn, userId);
            crsReport = JSONObject.parseObject(data2.toJSONString(), CustomerCrsReport.class);
            crsReport.setStatus("1");
            JSONObject paymentFile = getPaymentProfile(registerId, userId);
            Object paymentProfiles = paymentFile.get("PaymentProfiles");
            crsReport.setPaymentProfiles(Func.isEmpty(paymentProfiles) ? null : paymentProfiles.toString());
            Object customers = paymentFile.get("Customers");
            crsReport.setCustomers(Func.isEmpty(customers) ? null : customers.toString());
            Object worstStatus = paymentFile.get("WorstStatus");
            crsReport.setWorstStatus(Func.isEmpty(worstStatus) ? null : worstStatus.toString());
            crsReport.setCreateTime(new Date());
            crsReport.setBvn(bvn);
            JSONObject fileJson = new JSONObject();
            fileJson.put("data2", data2);
            fileJson.put("paymentFile", paymentFile);
            String path = "crs";
            //crsReport.setReportResult(fileService.createJsonFileToServer(fileJson));
            crsReport.setAwsS3Url(fileService.createJsonFile(fileJson, path));
        } catch (Exception e) {
            crsReport.setRemark(e.getMessage());
            crsReport.setStatus("0");
            log.error("创建CRS报告异常", e);
            throw e;
        } finally {
            crsReport.setBvn(bvn);
            crsReport.setUserId(userId);
            crsReport.setCustNo(getCustNoByUserId(userId));
            crsReportService.insertCustomerCrsReport(crsReport);
        }
        return crsReport;
    }


    private String getCustNoByUserId(String userId) {
        CustomerInfo customerInfo = new CustomerInfo();
        customerInfo.setUserId(userId);
        customerInfo.setState(BizConstants.BIZ_STATUS_1);
        List<CustomerInfo> customerInfoList = customerInfoService.selectCustomerInfoList(customerInfo);
        if (CollectionUtils.isEmpty(customerInfoList)) {
            throw new BusinessException(RspEnmu.CUSTOMER_IS_NOT_EXISTS);
        }

        return customerInfoList.get(0).getCustNo();
    }

    public JSONObject crsRequest(JSONObject params, String url, String name, String userId) {

        Headers.Builder headersBuilder = new Headers.Builder();
        headersBuilder.add("Content-Type", "application/json");
        Headers headers = headersBuilder.build();
        OkRequestVo post = OkRequestVo.builder().apiName(name).url(url).reqMethod("POST").params(params).reqEnum(ExtReqEnum.JSON).headers(headers).build();
        post.setUserId(userId);
        JSONObject resultJson = iExternalApiService.crsRequest(post);
        if ("false".equals(resultJson.get("Success").toString())) {
            log.error("CRS请求异常，url:{},报文:{}", url, resultJson);
            return null;
        }
        return resultJson;
    }

    public static String commaConvertSpace(String str) {
        return Func.isEmpty(str) ? str : str.replaceAll(",", " ");
    }


}
